#include "kernel/astralapi.h"
#include "tester.h"
#include "strapi.h"

int arch_get_cpuid();

unsigned long counter_spin;
struct AstralSpin spin;
static struct AstralSem sem;

#define N (10)

int do_spin_test(void *arg)
{
    AstralTask self = get_curr_task();
    for (int i = 0; i < 10; i++)
    {
        spin_lock(&spin);
        int a = counter_spin;
        for (int k = 0; k < 1000; k++)
        {
        }
        a++;
        counter_spin = a;
        spin_unlock(&spin);
    }
    kprint("[%s]:%d counter_spin=%d runs on %d\n",
           self->name,
           CAST_AS(int, arg),
           counter_spin,
           arch_get_cpuid());
    release_sem(&sem);
    return 0;
}

static void description()
{
    kprint("\n\nSPINLOCK Test\n"
           "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
           "%d Tasks named spin-xxx will be created.\n"
           "passed if final counter is %d\n\n",
           N, N * 10);
}

boolean spin_test(void *arg)
{
    static boolean first = True;
    if(first)
    {
        create_sem(&sem);
        first = False;
    }
    description();

    counter_spin = 0;

#ifdef CFG_NO_TASK_POOL
    static struct AstralTask tasks[N];
    static char stack[N][1024];
    char localname[15];
    for (int i = 0; i < N; i++)
    {
        snprintf(localname, 15, "spin-%-03d", i);
        struct AstralAttr attr = {
            .base = &stack[i],
            .stack_size = 1024,
            .priority = 16,
            .name = localname};
        create_task(&tasks[i], &attr, do_spin_test, CAST_AS(object, i));
    }
    for (int i = 0; i < N; i++)
    {
        distach_task(&tasks[i]);
    }
#else
    AstralTaskPool pool = CAST_AS(AstralTaskPool, arg);
    for(int i=0; i<N; i++)
    {
        pool_dispatch_job(pool, do_spin_test, CAST_AS(object, i));
    }
#endif

    for (int i = 0; i < N; i++)
    {
        obtain_sem(&sem);
    }

    return (counter_spin % (10*N) == 0);
}


DEFINE_TEST(spin_test)